#include<bits/stdc++.h>
#define int long long 
using namespace std;
const int maxn=1e5+10;
int n, m;

// Kruskal 对边权从大到小排序,每次选小的, 并且能够添加新节点的
struct Edge{
	int x,y,c;
	bool operator < (const Edge & e) {
		return c==e.c? x<e.x : c<e.c;
	}
};

vector<Edge> es;
int pre[maxn]; // 并查集

int root(int x){
	return pre[x]=(x==pre[x]?x:root(pre[x])); // 采用了路径优化
}

void solve(){
	cin>>n>>m;
	int ans=0;
	for(int i=1;i<=m;i++){
		int x,y,c;
		cin>>x>>y>>c;
		es.push_back({x, y, c});
	}
	
	for(int i=1;i<=n;i++){
		pre[i]=i;
	}
	sort(es.begin(), es.end()); // 边权从小到大排序
	for(Edge e: es){
		if(root(e.x)!=root(e.y)) { // 注意这里是一条边的两个节点之间进行比较
			pre[root(e.x)]=root(e.y); // 添加新节点
			ans=max(ans, e.c);
		}
	}
	cout<<ans<<'\n';
}

signed main(){
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	int t;
	cin>>t;
	while(t--){
		es.clear();
		memset(pre, 0, sizeof(pre));
		solve();
	}
	return 0;
}
